package com.watson.minio.springminio.file.controller;

import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;
import com.watson.minio.springminio.file.entity.User;
import com.watson.minio.springminio.file.util.FileUtils;
import com.watson.minio.springminio.file.util.PDFUtils;
import com.watson.minio.springminio.file.util.Result;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @Description: TODO
 * @Author watson
 * @Date 2022/7/13 11:32
 * @Version 1.0
 */
@RestController
@RequestMapping("demo")
@Slf4j
@Api(tags = "一般文件上传")
public class FileController {
    @Value("${com.cpiinfo.iot.file.commonPath}")
    private String filePatha;

    @ApiOperation(value = "pdf预览1", notes = "pdf预览1")
    @GetMapping("/preview1")
    public void er(HttpServletResponse response) {
        InputStream input = FileController.class.getClassLoader().getResourceAsStream("doc/深入浅出设计模式(中文版).pdf");
        byte[] data = null;
        try {
            data = new byte[input.available()];
            input.read(data);
            response.getOutputStream().write(data);
            input.close();
        } catch (Exception e) {
            System.out.println(e);
        }
    }

    @ResponseBody
    @GetMapping("/preview2")
    @ApiOperation(value = "pdf预览2", notes = "pdf预览2")
    public void findPdf(HttpServletResponse response) throws IOException {
        response.setContentType("application/pdf");
//        FileInputStream in = new FileInputStream(new File("G:\\桌面\\Thymeleaf3.0中文翻译文档@www.java1234.com.pdf"));
        InputStream in = FileController.class.getClassLoader().getResourceAsStream("doc/深入浅出设计模式(中文版).pdf");
        OutputStream out = response.getOutputStream();
        byte[] b = new byte[512];
        while ((in.read(b)) != -1) {
            out.write(b);
        }
        out.flush();
        in.close();
        out.close();
    }

    @ResponseBody
    @GetMapping("/preview3")
    @ApiOperation(value = "pdf预览3", notes = "pdf预览3")
    public void devDoc(HttpServletRequest request, HttpServletResponse response, String storeName) throws Exception {
        request.setCharacterEncoding("UTF-8");
        String ctxPath = request.getSession().getServletContext().getRealPath("");
        String downLoadPath = "G:\\桌面\\Thymeleaf3.0中文翻译文档@www.java1234.com.pdf";
        response.setContentType("application/pdf");
//        FileInputStream in = new FileInputStream(new File(downLoadPath));
        InputStream in = FileController.class.getClassLoader().getResourceAsStream("doc/深入浅出设计模式(中文版).pdf");
        OutputStream out = response.getOutputStream();
        byte[] b = new byte[1024];
        while ((in.read(b)) != -1) {
            out.write(b);
        }
        out.flush();
        in.close();
        out.close();
    }

    @GetMapping(value = "/showpdf")
    @ApiOperation(value = "pdf预览4", notes = "pdf预览4")
    public void showpdf(HttpServletRequest request, HttpServletResponse response, Model model) {
        try {
            File file = new File("D:/xyptFile/java.pdf");
            FileInputStream fileInputStream = new FileInputStream(file);
            response.setHeader("Content-Type", "application/pdf");
            OutputStream outputStream = response.getOutputStream();
            IOUtils.write(IOUtils.toByteArray(fileInputStream), outputStream);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    @GetMapping("/download")
    @ApiOperation(value = "文件下载", notes = "文件下载")
    public void zcTemplateDown(HttpServletRequest request, HttpServletResponse response,
                               @RequestParam(value = "moduleTye", required = false) String moduleTye) throws Exception {
        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        String fileName = "深入浅出设计模式(中文版).pdf";
        // 下载所有类型的模板《方阵、物理设备、组串组件》
        if (StringUtils.isNotBlank(moduleTye)) {
            fileName = moduleTye + ".pdf";
        }
        try {
            response.setContentType("multipart/form-data;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            InputStream inputStream = FileController.class.getClassLoader().getResourceAsStream("doc/" + fileName);
            OutputStream os = response.getOutputStream();
            byte[] b = new byte[2048];

            int length;
            while ((length = inputStream.read(b)) > 0) {
                os.write(b, 0, length);
            }

            os.close();
            inputStream.close();
        } catch (Exception var7) {
            var7.printStackTrace();
        }
    }

    @PostMapping("/upFile")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "path", value = "路径（文件夹名称）", paramType = "query", dataType = "String"),
            @ApiImplicitParam(name = "file", value = "文件", paramType = "query", dataType = "String"),
    })
    @ApiOperation(value = "文件上传", notes = "文件上传")
    public Result upFile(String path, MultipartFile mfile) {
        if (mfile == null || mfile.getSize() <= 0) {
            return new Result().error("上传文件不能为空");
        }

        String savePath = filePatha;
        if (StringUtils.isNotBlank(path)) {
            savePath = savePath + File.separator + path;
        }

        if (!FileUtils.isDir(savePath)) {
            FileUtils.makeDirs(savePath);
        }

        String url = savePath + File.separator + mfile.getOriginalFilename();
        File file = new File(url);
        try {
            mfile.transferTo(file);
        } catch (IOException e) {
            return new Result().error("上传失败");
        }

        return new Result().ok("操作成功", url);
    }

    @PostMapping("/uploadFile")
    @ApiOperation(value = "文件上传", notes = "文件上传")
    public Result uploadFile(MultipartFile multipartFile) {
        if (multipartFile == null || multipartFile.getSize() <= 0) {
            return new Result().error("上传文件不能为空");
        }
        if (multipartFile.getSize() > 1024 * 1024 * 10) {
            return new Result().error("上传文件不能为超过10M");
        }

        String savePath = filePatha;
        if (!FileUtils.isDir(savePath)) {
            FileUtils.makeDirs(savePath);
        }
        String originalFilename = multipartFile.getOriginalFilename();
        String url = savePath + File.separator + originalFilename;
        File file = new File(url);
        try {
            multipartFile.transferTo(file);
        } catch (IOException e) {
            log.info("上传失败", e);
            return new Result().error("上传失败");
        }

//        String substring = url.substring(0, originalFilename.lastIndexOf("."));
        String substring = originalFilename.substring(0, originalFilename.lastIndexOf("."));
        //如果上传的是zip文件则解压
        if (originalFilename.endsWith(".zip")) {
            String savezipPath = savePath + File.separator + substring + File.separator; //保存解压文件目录
            if (!FileUtils.isDir(savezipPath)) {
                FileUtils.makeDirs(savezipPath);
            }

            ZipEntry zipEntry = null;
            try (
                    // ZipInputStream读取压缩文件
                    ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(savePath + File.separator + originalFilename), Charset.forName("GBK"));
                    // 写入到缓冲流中
                    BufferedInputStream bufferedInputStream = new BufferedInputStream(zipInputStream);
            ) {
                File fileOut = null;
                // 读取压缩文件中的一个文件
                while ((zipEntry = zipInputStream.getNextEntry()) != null) {
                    // 若当前zipEntry是一个文件夹
                    if (zipEntry.isDirectory()) {
                        fileOut = new File(savePath + "//" + zipEntry.getName());
                        // 在指定路径下创建文件夹
                        if (!fileOut.exists()) {
                            fileOut.mkdirs();
                        }
                        //若是文件
                    } else {
                        // 原文件名与指定路径创建File对象(解压后文件的对象)
                        fileOut = new File(savePath, zipEntry.getName());
                        try (
                                FileOutputStream fileOutputStream = new FileOutputStream(fileOut);
                                BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);) {
                            //将文件写入到指定file中
                            int b = 0;
                            while ((b = bufferedInputStream.read()) != -1) {
                                bufferedOutputStream.write(b);
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            } catch (Exception e) {
                log.info("infra_station_map upload file exception", e);
            }


        }
        return new Result().ok("操作成功", substring);
    }


    @ApiOperation(value = "导出PDF异常报告", notes = "导出PDF异常报告")
    @GetMapping("/exportPDFDiagReport")
    @ApiImplicitParam(name = "stationId", value = "场站id", paramType = "query", dataType = "Long")
    @ResponseBody
    public void exportPDFReport(Long stationId,  HttpServletRequest request, HttpServletResponse response) {
        try {
            request.setCharacterEncoding("utf-8");
            response.setCharacterEncoding("utf-8");
            String path = "/home/data" + File.separator;
            String pdfName = getPdfName(new ArrayList<>(), "");
            downLoad(response, pdfName, path);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void downLoad(HttpServletResponse response, String fileName, String path) {
        try {
            response.setContentType("multipart/form-data;charset=UTF-8");
            response.setHeader("Content-Disposition", "attachment; fileName=" + URLEncoder.encode(fileName, "UTF-8"));
            File file = new File(path);
            if (!file.exists()) {
                file.mkdirs();
            }
            InputStream inputStream = new FileInputStream(new File(path + fileName));

            OutputStream os = response.getOutputStream();
            byte[] b = new byte[2048];

            int length;
            while ((length = inputStream.read(b)) > 0) {
                os.write(b, 0, length);
            }

            os.close();
            inputStream.close();
        } catch (Exception var7) {
            var7.printStackTrace();
        }

    }




    private String getPdfName(List<User> warns, String stationName) {
        //2.根据区域查询设备数和异常类型,表头信息
        long deviceCount = warns.stream().filter(distinctByKey(User::getId)).count();
        long warnTypeCount = warns.stream().filter(distinctByKey(User::getId)).count();
        //根据区域id分类
        Map<Long, List<User>> areaWarns = warns.stream().collect(Collectors.groupingBy(User::getAreaId));

        //查询场站名称
        Date nowDate = new Date();
        DateFormat dateInstance = DateFormat.getDateInstance();
        DateFormat dateInstance2 = DateFormat.getDateTimeInstance();
        String date = dateInstance.format(nowDate);
        String pdfName = stationName + date + "截止现存异常报告";
        //制表
        String errMsg = null;
        BaseFont simpChinese;
        Font fontChineseNormal = PDFUtils.createFont(11, Font.NORMAL);
        Font fontChineseBold = PDFUtils.createFont(14, Font.BOLD);
        if (! isDir(filePatha)) {
            makeDirs(filePatha);
        }
        try {
            Document document = new Document();
            PdfWriter.getInstance(document, new FileOutputStream(filePatha + "/" + pdfName + ".pdf"));
            // 标题
            Paragraph titleParagraph = new Paragraph();
            titleParagraph.add(new Chunk(pdfName, PDFUtils.createFont(26, Font.BOLD)));
            titleParagraph.setLeading(26f);
            titleParagraph.add(new Chunk(("\n")));
            titleParagraph.add("\n");
            titleParagraph.setAlignment(Element.ALIGN_CENTER);
            document.open();
            document.add(titleParagraph);
            // 统计部分
            Paragraph countParagraph = new Paragraph();
            PdfPTable tableHead = PDFUtils.createTable(2, 500, Element.ALIGN_CENTER);
            tableHead.getDefaultCell().setBorder(15); // 设置表格默认为无边框
            PdfPCell c1 = PDFUtils.createCell("场站名称：" + stationName, fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_LEFT);
            c1.setBorderColor(BaseColor.WHITE);
            PdfPCell c2 = PDFUtils.createCell("生成日期：" + dateInstance2.format(nowDate), fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_LEFT);
            c2.setBorderColor(BaseColor.WHITE);
            PdfPCell c3 = PDFUtils.createCell("异常设备数：" + deviceCount, fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_LEFT);
            c3.setBorderColor(BaseColor.WHITE);
            PdfPCell c4 = PDFUtils.createCell("异常类型：" + warnTypeCount, fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_LEFT);
            c4.setBorderColor(BaseColor.WHITE);
            tableHead.addCell(c1);
            tableHead.addCell(c2);
            tableHead.addCell(c3);
            tableHead.addCell(c4);
            countParagraph.add(tableHead);
            countParagraph.add(new Chunk(("\n")));
            countParagraph.setIndentationLeft(10);
            countParagraph.setSpacingAfter(10);
            document.add(countParagraph);
            //内容部分
            Paragraph contentTitleParagraph = new Paragraph("巡检结果分析：", PDFUtils.createFont(16, Font.BOLD));

            //遍历区域map--子阵
            for (List<User> areaWarn : areaWarns.values()){
                //查出该区域下的异常种类数量
                long count = areaWarn.stream().filter(distinctByKey(User::getId)).count();
                PdfPTable tableDetail = PDFUtils.createTable((int)count + 1, 500, Element.ALIGN_CENTER);
                //安异常分类分组
                Map<Long, List<User>> typeWarns = areaWarn.stream().collect(Collectors.groupingBy(User::getId));
                String areaName = areaWarn.get(0).getUsername();
                PdfPCell cell1 = PDFUtils.createCell(areaName, fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_CENTER);
                cell1.setBackgroundColor(new BaseColor(246,247,251,1));
                tableDetail.addCell(cell1);
                for (List<User> warn : typeWarns.values()){
                    //获取异常分类名称
                    String typeName = warn.get(0).getUsername();
                    int count1 = warn.size();
                    PdfPCell cell = PDFUtils.createCell(typeName + "：" + count1 + "处", fontChineseBold, Element.ALIGN_TOP, Element.ALIGN_CENTER);
                    tableDetail.addCell(cell);
                }
                contentTitleParagraph.add(tableDetail);
            }
            contentTitleParagraph.add(new Chunk(("\n")));
            document.add(contentTitleParagraph);

            //故障详情
            Paragraph warnDetailParagraph = new Paragraph("故障详情：", PDFUtils.createFont(16, Font.BOLD));

            //根据设备kks分类
            Map<String, List<User>> deviceWarns = warns.stream().collect(Collectors.groupingBy(User::getPassword));
            for (List<User> reportWarns : deviceWarns.values()) {
                //告警详情
                PdfPTable tableWarnDetail1 = PDFUtils.createTable( 1, 500, Element.ALIGN_CENTER);
                PdfPTable tableWarnDetail2 = PDFUtils.createTable( new float[]{95,135,135,135}, 500, Element.ALIGN_CENTER);
                String areaName = reportWarns.get(0).getUsername();
                String deviceName = reportWarns.get(0).getUsername();
                PdfPCell cell1 = PDFUtils.createCell("设备区域：" + areaName + new Chunk(("\n\n")), fontChineseBold, Element.ALIGN_CENTER, Element.ALIGN_LEFT);
                cell1.setBorderColor(BaseColor.WHITE);
                tableWarnDetail1.addCell(cell1);

                PdfPCell cell3 = PDFUtils.createCell("设备名称：" + deviceName, fontChineseBold, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);
                cell3.setBackgroundColor(new BaseColor(246,247,251,1));
                cell3.setRowspan(reportWarns.size());
                tableWarnDetail2.addCell(cell3);
                for (User warn : reportWarns){
                    PdfPCell cell4 = PDFUtils.createCell("告警编号：" + warn.getId() + new Chunk(("\n")) + "告警类型：" + warn.getUsername() + new Chunk(("\n")) + "诊断时间：" + dateInstance2.format(warn.getCreateTime()), fontChineseBold, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);
                    //获取图片
                    String url = warn.getUrl();
                    String[] split = StringUtils.split(url, ",");
                    //可见光地址
                    String visibleLightPath = split[0];
                    Image bmp = null;
                    if (StringUtils.isNotBlank(visibleLightPath)) {
                        if (exists(visibleLightPath)) {
                            bmp = Image.getInstance(visibleLightPath);
                        }
                    }
                    PdfPCell cell5 = PDFUtils.createCell(null, fontChineseNormal, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);//可见光
                    PdfPCell cell6 = PDFUtils.createCell(null, fontChineseNormal, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);//红外光
                    tableWarnDetail2.addCell(cell4);
                    if (bmp != null){
                        cell5.addElement(bmp);
                        tableWarnDetail2.addCell(cell5);
                    }else{
                        PdfPCell cell7 = PDFUtils.createCell("无可见光图片或地址有误", fontChineseNormal, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);//可见光
                        cell7.setBackgroundColor(new BaseColor(232,237,249,1));
                        tableWarnDetail2.addCell(cell7);
                    }
                    //红外光地址
                    String infraredLightPath = null;
                    if (split.length > 1){
                        infraredLightPath = split[1];
                    }

                    Image bmp2 = null;
                    if (StringUtils.isNotBlank(infraredLightPath)) {
                        if (exists(infraredLightPath)) {
                            bmp2 = Image.getInstance(infraredLightPath);
                        }
                    }
                    if(bmp2 != null){
                        cell6.addElement(bmp2);
                        tableWarnDetail2.addCell(cell6);
                    }else {
                        PdfPCell cell7 = PDFUtils.createCell("无红外光图片或地址有误", fontChineseNormal, Element.ALIGN_MIDDLE, Element.ALIGN_CENTER);//可见光
                        cell7.setBackgroundColor(new BaseColor(232,237,249,1));
                        tableWarnDetail2.addCell(cell7);
                    }
                }
                tableWarnDetail2.setSpacingAfter(20);
                warnDetailParagraph.add(tableWarnDetail1);
                warnDetailParagraph.add(tableWarnDetail2);

            }
            document.add(warnDetailParagraph);

            document.close();
        }catch (Exception e){
            e.printStackTrace();
            errMsg = "导出pdf过程异常" + e.getMessage();
        }

        return pdfName + ".pdf";
    }

    public static boolean exists(String path) {
        return (new File(path)).exists();
    }


    private static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
        Map<Object, Boolean> seen = new ConcurrentHashMap<>();
        return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
    }
    public static boolean isDir(String dirPath) {
        File f = new File(dirPath);
        return f.exists() && f.isDirectory();
    }
    public static void makeDirs(String path) {
        File file = new File(path);
        if (!file.exists() && !file.isDirectory()) {
            file.mkdirs();
        } else {
            System.out.println("创建目录失败：" + path);
        }
    }

}
